package dao

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/olivere/elastic/v7"
	"grpc-common/search/types/search"
	"listenboos-common/kafka/model"
	"log"
	m "search/model"
	"strconv"
	"strings"
)

const AlbumIndexName = "album_index"
const Suggest = "suggest_info"

type AlbumElasticDAO struct {
	Client *elastic.Client
}

func NewAlbumElasticDAO() *AlbumElasticDAO {
	opts := []elastic.ClientOptionFunc{
		elastic.SetURL("http://192.168.2.9:9200"),
		elastic.SetSniff(false), // 禁用 sniffing（在生产环境中应启用）
	}
	client, err := elastic.NewClient(opts...)
	if err != nil {
		panic(err)
	}

	return &AlbumElasticDAO{Client: client}
}
func (h *AlbumElasticDAO) SearchChannel(ctx context.Context, keywords []string) ([]model.AlbumInfo, error) {
	queryString := strings.Join(keywords, " ")
	topHitsAgg := elastic.NewTopHitsAggregation().
		Size(6).
		Sort("hotScore", true) // true 表示降序排序

	// 创建搜索服务并设置索引和聚合
	searchService := h.Client.Search().
		Index(AlbumIndexName).
		Aggregation("topSixHotScoreAgg", topHitsAgg)
	query := elastic.NewBoolQuery().Must(
		elastic.NewBoolQuery().Should(
			elastic.NewTermQuery("category3Id", queryString)))
	// 执行查询
	// result, err := searchService.Do(context.Background())
	resp, err := searchService.Query(query).Do(ctx)
	if err != nil {
		log.Fatalf("Error getting response: %s", err)
	}
	// 处理结果
	res := make([]model.AlbumInfo, 0, len(resp.Hits.Hits))
	for _, hit := range resp.Hits.Hits {
		var ele model.AlbumInfo
		err = json.Unmarshal(hit.Source, &ele)
		res = append(res, ele)
	}
	return res, nil
}

func (h *AlbumElasticDAO) Search(ctx context.Context, keywords []string) ([]model.AlbumInfo, error) {
	queryString := strings.Join(keywords, " ")
	query := elastic.NewBoolQuery().Must(
		elastic.NewBoolQuery().Should(
			elastic.NewMatchQuery("albumTitle", queryString),
			elastic.NewMatchQuery("albumIntro", queryString)),
		elastic.NewTermQuery("is_open", 1))
	resp, err := h.Client.Search(AlbumIndexName).Query(query).Do(ctx)
	if err != nil {
		return nil, err
	}
	res := make([]model.AlbumInfo, 0, len(resp.Hits.Hits))
	for _, hit := range resp.Hits.Hits {
		var ele model.AlbumInfo
		err = json.Unmarshal(hit.Source, &ele)
		res = append(res, ele)
	}
	return res, nil
}
func (h *AlbumElasticDAO) SearchAlbumInfo(ctx context.Context, req *search.AlbumInfoReq, PageNo int64, pageSize int64) ([]model.AlbumInfo, int64, int64, error) {
	keywords := []string{req.KeyWord}
	queryString := strings.Join(keywords, " ")
	boolQuery := elastic.NewBoolQuery()
	// 构建bool查询
	query := elastic.NewBoolQuery().Must(
		boolQuery.Should(
			elastic.NewMatchQuery("albumTitle", queryString),
			elastic.NewMatchQuery("albumIntro", queryString)),
	)
	if req.Category3Id != 0 {
		category3IdFilter := elastic.NewTermQuery("category3Id", req.Category3Id)
		boolQuery.Filter(category3IdFilter)
	}
	//nestedQuery := elastic.NewNestedQuery("attributeValueIndexList",
	//	elastic.NewBoolQuery().Must(
	//		elastic.NewTermQuery("attributeValueIndexList.attributeId", req.),
	//		elastic.NewTermQuery("attributeValueIndexList.valueId", "21"),
	//	),
	//)
	// 设置排序和高亮

	highlight := elastic.NewHighlight().
		Field("albumTitle").
		PreTags("<font color='red'>").
		PostTags("</font>")
	//gradeField := elastic.NewHighlighterField("grade").PreTags("<font color='red'>").
	//	PostTags("</font>")
	//highlight = elastic.NewHighlight().Fields(gradeField)
	offset := (PageNo - 1) * pageSize
	resp, err := h.Client.Search(AlbumIndexName).Query(query).Highlight(highlight).Sort("playStatNum", true).From(int(offset)).Size(int(pageSize)).Do(ctx)

	//resp, err = h.Client.Search(AlbumIndexName).Query(query).Do(ctx)
	if err != nil {
		return nil, 0, 0, err
	}
	res := make([]model.AlbumInfo, 0, len(resp.Hits.Hits))
	for _, hit := range resp.Hits.Hits {
		var ele model.AlbumInfo
		err = json.Unmarshal(hit.Source, &ele)
		// 获取高亮字段
		if light, ok := hit.Highlight["albumTitle"]; ok {
			fmt.Printf("Highlight: %s\n", light[0]) // 通常高亮结果是一个数组，取第一个元素
		} else {
			// 将Source字段的[]byte转换为字符串并打印
			sourceStr := string(hit.Source)
			fmt.Printf("Raw document (JSON string): %s\n", sourceStr)

			// 如果你需要将Source字段解析为map[string]interface{}，可以使用json.Unmarshal
			var sourceMap map[string]interface{}
			err := json.Unmarshal(hit.Source, &sourceMap)
			if err != nil {
				log.Printf("Error unmarshaling source: %s", err)
				continue
			}
			fmt.Println(sourceMap)
			fmt.Printf("No highlight found for field 'field_name'\n")
		}
		res = append(res, ele)
	}
	total := resp.Hits.TotalHits.Value
	totalPages := (total + pageSize - 1) / pageSize
	return res, total, totalPages, nil
}
func (h *AlbumElasticDAO) InputAlbum(ctx context.Context, art model.AlbumInfo) error {
	_, err := h.Client.Index().
		Index(AlbumIndexName).
		Id(strconv.FormatInt(art.Id, 10)).
		BodyJson(art).Do(ctx)
	return err
}
func (h *AlbumElasticDAO) UpdateAlbumCount(ctx context.Context, artId int64, tp string, count int64) error {
	var art model.AlbumInfo
	getService := h.Client.Get().
		Index(AlbumIndexName).
		Id(strconv.FormatInt(artId, 10))
	res, err := getService.Do(ctx)
	if err != nil {
		log.Fatalf("无法检索文档: %v", err)
	}
	if err := json.Unmarshal(res.Source, &art); err != nil {
		log.Fatalf("无法解析文档内容: %v", err)
	}
	if tp == "buyStatNum" {
		num := art.BuyStatNum
		art.BuyStatNum = num + count
	}
	if tp == "playStatNum" {
		num := art.PlayStatNum
		art.PlayStatNum = num + count
	}
	if tp == "commentStatNum" {
		num := art.CommentStatNum
		art.CommentStatNum = num + count
	}
	if tp == "subscribeStatNum" {
		num := art.SubscribeStatNum
		art.SubscribeStatNum = num + count
	}
	_, err = h.Client.Index().
		Index(AlbumIndexName).
		Id(strconv.FormatInt(art.Id, 10)).
		BodyJson(art).Do(ctx)
	return err
}

//	func (h *AlbumElasticDAO) UpdateTrackCollectCount(ctx context.Context, artId int64, ) error {
//		var art model.AlbumInfo
//		getService := h.Client.Get().
//			Index(AlbumIndexName).
//			Id(strconv.FormatInt(artId, 10))
//		res, err := getService.Do(ctx)
//		if err != nil {
//			log.Fatalf("无法检索文档: %v", err)
//		}
//		if err := json.Unmarshal(res.Source, &art); err != nil {
//			log.Fatalf("无法解析文档内容: %v", err)
//		}
//		if tp == "commentStatNum" {
//			num := art.CommentStatNum
//			art.CommentStatNum = num + count
//		}
//		_, err = h.Client.Index().
//			Index(AlbumIndexName).
//			Id(strconv.FormatInt(art.Id, 10)).
//			BodyJson(art).Do(ctx)
//		return err
//	}
func (h *AlbumElasticDAO) FindAlbumInfo(ctx context.Context, keyWord string) (m.Album, error) {
	//keywords := []string{keyWord}
	//queryString := strings.Join(keywords, " ")
	//query := elastic.NewBoolQuery().Must(
	//	elastic.NewBoolQuery().Should(
	//		elastic.NewMatchQuery("id", queryString)))
	resp, err := h.Client.Get().Index(AlbumIndexName).Id(keyWord).Do(ctx)
	if err != nil {
		return m.Album{}, err
	}
	var e m.Album

	err = json.Unmarshal(resp.Source, &e)

	return e, nil
}

// GET album_index/_search
// {
// "query": {
// "match_all": {}
// },
// "sort":[
// {
// "playStatNum": {
// "order": "desc"
// }
// }
// ]
// }
func (h *AlbumElasticDAO) UpdateRanking(ctx context.Context, category1Id int64, dimension string) ([]model.AlbumInfo, error) {
	// TODO:需要查询1级别分类id
	resp, err := h.Client.Search().Index(AlbumIndexName).Query(elastic.NewMatchQuery("category1Id", category1Id)).Size(10).Sort(dimension, true).Do(ctx)
	if err != nil {
		return nil, err
	}
	res := make([]model.AlbumInfo, 0, len(resp.Hits.Hits))
	for _, hit := range resp.Hits.Hits {
		var ele model.AlbumInfo
		err = json.Unmarshal(hit.Source, &ele)
		res = append(res, ele)
	}
	return res, nil
}
func (h *AlbumElasticDAO) KeyWord(ctx context.Context, Keywords []string) ([]string, error) {
	return nil, nil
}
